#include "Sync_Directory.h"
#include <stdexcept>
#include <boost/foreach.hpp>


Sync_Directory::Sync_Directory(boost::filesystem::path xpath) :
    Sync_File(xpath)
{
}

Sync_Directory::~Sync_Directory()
{
}


/* to be called in the ariba-thread */
void Sync_Directory::scan(boost::shared_ptr<ScanCompletedInterface> listener)
{
    if ( ! scanning )
    {
        scanning = true;
        scan_listener = listener;

        runBlockingMethod();
    }
}


/* to be called outside the ariba-thread (and only once at a time) */
void Sync_Directory::scan_raw()
{
    // BRANCH: exist on hard disk
    if ( boost::filesystem::is_directory(get_whole_path()) )
    {
        shadow_locally = true;

        directory_iterator end;
        for ( directory_iterator it(get_whole_path()); it != end; ++it )
        {
            // BRANCH: directory
            if ( boost::filesystem::is_directory(it->path()) )
            {
    //            cout << "[DIR] " << it->path().string() << endl;  // XXX

                SyncDirPtr dir(new Sync_Directory(common_path / it->path().filename()));
                dir->set_base_path(base_path);
                dir->set_exist_locally(true);
                shadow_subdirs.push_back(dir);
            }
            // BRANCH: file
            else if ( boost::filesystem::is_regular(it->path()) )
            {
                boost::uintmax_t size = boost::filesystem::file_size(it->path());
    //            cout << "[FILE] " << it->path().string() << " (size: " << size << ")" << endl;  // XXX

                // TODO, vielleicht gleich noch Größe und Rechte mit einlesen?
                SyncRegularFilePtr file(new Sync_Regular_File(common_path / it->path().filename()));
                file->set_base_path(base_path);
                file->set_exist_locally(true);
                file->set_estimatedsize(size);
                shadow_subfiles.push_back(file);
            }
        }
    }

    // BRANCH: does not exist locally
    else
    {
        shadow_locally = false;
    }
}


void Sync_Directory::blockingFunction()
{
    scan_raw();
    dispatch();
}



// synchronizes scan thread with ariba thread
void Sync_Directory::dispatchFunction()
{
    scanning = false;
    transparent = true;
    exist_locally = shadow_locally;

    // TODO was machen wir hier, wenn die Einträge aus subdirs und subfiles in Benutzung sind?
    // Dann müssen wir sie hier irgendwie anpassen, anstelle sie einfach wegzuwerfen. Hm :-/

    // swap
    subdirs.swap(shadow_subdirs);
    subfiles.swap(shadow_subfiles);

    // clear
    shadow_subdirs.clear();
    shadow_subfiles.clear();


    // XXX debug
    cout << "+++ TESTING Directory Scan +++" << endl;
    BOOST_FOREACH(SyncDirPtr dir, subdirs)
    {
        cout << "[DIR] " << dir->get_whole_path() << endl;
    }
    BOOST_FOREACH(SyncRegularFilePtr file, subfiles)
    {
        cout << "[FILE] " << file->get_whole_path() << endl;
    }


    // inform scan_listener that we're done, reset scan_listener
    boost::shared_ptr<ScanCompletedInterface> listener;
    listener.swap(scan_listener);
    listener->scan_completed_callback();
}



vector<boost::shared_ptr<Sync_Directory> > Sync_Directory::get_subdirs() const
{
    return subdirs;
}

vector<boost::shared_ptr<Sync_Regular_File> > Sync_Directory::get_subfiles() const
{
    return subfiles;
}

boost::shared_ptr<Sync_Directory> Sync_Directory::get_subdir(boost::filesystem::path filename)
{
    BOOST_FOREACH(SyncDirPtr dir, subdirs)
    {
        if ( dir->get_common_path().filename() == filename )
        {
            return dir;
        }
    }

    // ERR: not found
    boost::shared_ptr<Sync_Directory> empty;
    return empty;
}

boost::shared_ptr<Sync_Regular_File> Sync_Directory::get_subfile(boost::filesystem::path filename)
{
    BOOST_FOREACH(SyncRegularFilePtr file, subfiles)
    {
        if ( file->get_common_path().filename() == filename )
        {
            return file;
        }
    }

    // ERR: not found
    throw not_found_exception(filename.string() + " not found.");
}

bool Sync_Directory::add_subdir(SyncDirPtr dir)
{
    subdirs.push_back(dir);

    return true;
}

bool Sync_Directory::add_subfile(SyncRegularFilePtr file)
{
    subfiles.push_back(file);

    return true;
}





